#include "at32f435_437_board.h"
#include "at32f435_437_clock.h"

#include <string.h>
#include "FreeRTOS.h"
#include "task.h"

#include "u8g2_hal.h"
#include "u8g2.h"

#include "bsp.h"
#include "oled_menu.h"
#include "llcc68.h"
#include "llcc68_drive.h"
#include "buzzer_control.h"

extern u8g2_t u8g2;
extern uint8_t need_confirm;
EventGroupHandle_t xLLCC68EventGroup;

void dump_task(void *pvParameters)
{
  char trace_buf[80];
  while(1)
  {
    debug_printf("================================\r\n");
    vTaskList(trace_buf);
    debug_printf("Free Heap: %d\r\n", xPortGetFreeHeapSize());
    debug_printf("%s", trace_buf);

    vTaskDelay(pdMS_TO_TICKS(5000));
  }
  vTaskDelete(NULL);
}

void vApplicationStackOverflowHook( TaskHandle_t xTask,
                                    char *pcTaskName )
{
  debug_printf("Stack Overflow: %s\r\n", pcTaskName);
}

void llcc68_buf_play(uint8_t *buf)
{
  if(!strncmp((char *)buf, "DO", sizeof("DO")))
  {
    buzzer_do();
  }
  if(!strncmp((char *)buf, "RE", sizeof("RE")))
  {
    buzzer_re();
  }
  if(!strncmp((char *)buf, "MI", sizeof("MI")))
  {
    buzzer_mi();
  }
  if(!strncmp((char *)buf, "FA", sizeof("FA")))
  {
    buzzer_fa();
  }
  if(!strncmp((char *)buf, "SOL", sizeof("SOL")))
  {
    buzzer_sol();
  }
  if(!strncmp((char *)buf, "LA", sizeof("LA")))
  {
    buzzer_la();
  }
  if(!strncmp((char *)buf, "SI", sizeof("SI")))
  {
    buzzer_si();
  }
}

void llcc68_tx_task(void *pvParameters)
{
  xLLCC68EventGroup = xEventGroupCreate();

  llcc68_chip_init();
  llcc68_set_tx_cfg(0xff);

  while(1)
  {
    EventBits_t uxBits;
    uxBits = xEventGroupWaitBits(
               xLLCC68EventGroup,
               DIO_DONE_BIT,
               pdTRUE,
               pdFALSE,
               pdMS_TO_TICKS(3000));

    llcc68_irq_mask_t llcc68_irq_mask;
    llcc68_get_and_clear_irq_status(NULL, &llcc68_irq_mask);
    if(uxBits & DIO_DONE_BIT)
    {
      if(llcc68_irq_mask & LLCC68_IRQ_RX_DONE)
      {
        llcc68_rx_buffer_status_t llcc68_rx_buffer_status;
        llcc68_get_rx_buffer_status(NULL, &llcc68_rx_buffer_status);

        //printf("%X,%X\r\n",llcc68_rx_buffer_status.buffer_start_pointer, llcc68_rx_buffer_status.pld_len_in_bytes);
        uint8_t read_buf[255];
        read_buf[llcc68_rx_buffer_status.pld_len_in_bytes] = '\0';
        llcc68_read_buffer(NULL, llcc68_rx_buffer_status.buffer_start_pointer, read_buf, llcc68_rx_buffer_status.pld_len_in_bytes);
        //uart_printf_rtos("%s\r\n", red_buf);

        llcc68_pkt_status_lora_t llcc68_pkt_status_lora;
        llcc68_get_lora_pkt_status(NULL, &llcc68_pkt_status_lora);

        char pkt_buf[32];
        char pkt_buf1[32];
        char pkt_buf2[32];
        sprintf(pkt_buf, "rssi_pkt_in_dbm=%d", llcc68_pkt_status_lora.rssi_pkt_in_dbm);
        sprintf(pkt_buf1, "sig_dbm=%d", llcc68_pkt_status_lora.signal_rssi_pkt_in_dbm);
        sprintf(pkt_buf2, "snr_pkt_in_db=%d", llcc68_pkt_status_lora.snr_pkt_in_db);
        //uart_printf_rtos("rssi_pkt_in_dbm=%d,signal_rssi_pkt_in_dbm=%d,snr_pkt_in_db=%d\r\n",llcc68_pkt_status_lora.rssi_pkt_in_dbm,llcc68_pkt_status_lora.signal_rssi_pkt_in_dbm,llcc68_pkt_status_lora.snr_pkt_in_db);

        u8g2_ClearBuffer(&u8g2);
        //u8g2_SetFont(&u8g2, u8g2_font_6x13_tf);
        u8g2_DrawStr(&u8g2, 0, 0, (const char *)read_buf);
        u8g2_DrawStr(&u8g2, 0, 13, pkt_buf);
        u8g2_DrawStr(&u8g2, 0, 26, pkt_buf1);
        u8g2_DrawStr(&u8g2, 0, 39, pkt_buf2);
        u8g2_DrawStr(&u8g2, 0, 52, "Right to Confirm");
        u8g2_SendBuffer(&u8g2);
        need_confirm = 1;
        llcc68_buf_play(read_buf);

        llcc68_rx();
      }
      // rx done
      if(llcc68_irq_mask & LLCC68_IRQ_TX_DONE)
      {
        debug_printf("TX_DONE\r\n");
        menu_confirm("TX_DONE");
        llcc68_rx();
      }
      if(llcc68_irq_mask & LLCC68_IRQ_TIMEOUT)
      {
        debug_printf("TIMEOUT\r\n");
        menu_confirm("TIMEOUT");
        llcc68_rx();
      }
      if(llcc68_irq_mask & LLCC68_IRQ_HEADER_ERROR)
      {
        debug_printf("HEADER_ERR\r\n");
        menu_confirm("HEADER_ERR");
        llcc68_rx();
      }
      if(llcc68_irq_mask & LLCC68_IRQ_CRC_ERROR)
      {
        debug_printf("CRC_ERR\r\n");
        menu_confirm("CRC_ERR");
        llcc68_rx();
      }
      if(llcc68_irq_mask & LLCC68_IRQ_PREAMBLE_DETECTED)
      {
        debug_printf("PREAMBLE_DETECTED\r\n");
      }
      if(llcc68_irq_mask & LLCC68_IRQ_SYNC_WORD_VALID)
      {
        debug_printf("SYNC_WORD_VALID\r\n");
      }
      if(llcc68_irq_mask & LLCC68_IRQ_HEADER_VALID)
      {
        debug_printf("HEADER_VALID\r\n");
      }
    }
  }
  vTaskDelete(NULL);
}

void app_main(void *pvParameters)
{
  debug_printf_init();
  debug_printf("uart printf test\r\n");

  buzzer_init();
  u8g2_disp_init();
  oled_menu_init();

  xTaskCreate(button_scan_task, "button_scan_task", 80, NULL, 1, NULL);
  xTaskCreate(llcc68_tx_task, "llcc68_tx_task", 1024, NULL,1,NULL);

  // xTaskCreate(dump_task, "dump_task", 100, NULL, 1, NULL);
  vTaskDelete(NULL);
}

/**
  * @brief  main function.
  * @param  none
  * @retval none
  */
int main(void)
{
  nvic_priority_group_config(NVIC_PRIORITY_GROUP_4);
  system_clock_config();

  at32_board_init();
  xTaskCreate(app_main, "app_main", 200, NULL, 1, NULL);
  vTaskStartScheduler();

  while(1)
  {
  }
}
